import json
import re
import subprocess
import sys
import threading
import time
import webbrowser
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime, timedelta
from decimal import Decimal, InvalidOperation

import psutil
import requests
from DrissionPage import ChromiumPage, ChromiumOptions
from DrissionPage._elements.none_element import NoneElement
from DrissionPage.errors import PageDisconnectedError

from PyQt5.QtCore import Qt, QDate, pyqtSignal
from PyQt5.QtGui import QKeySequence, QPixmap, QPainter, QIcon
from PyQt5.QtSvg import QSvgRenderer
from PyQt5.QtWidgets import QApplication, QMainWindow, QShortcut, QMessageBox

from Ui_gangdi_calc import Ui_gangdi_calc


class MainApp(QMainWindow, Ui_gangdi_calc):
    # 定义信号
    show_warning_signal = pyqtSignal(str, str)

    def __init__(self, current_version):
        super().__init__()
        self.setupUi(self)
        self.init_icon()

        self.current_version = current_version
        self.current_version_label.setText(current_version)
        self.hotels_data = []  # 初始化 hotels_data 为一个空列表
        self.packages_data = []  # 初始化 packages_data 为一个空列表
        self.links_data = []
        self.ticket_levels = {}  # 存储门票等级数据
        self.fetch_ticket_levels()  # 初始化时获取并保存门票等级数据
        self.ticket_prices = {}  # 存储门票价格数据
        # 初始化标志位
        self.is_updating_package = False
        co = ChromiumOptions().set_argument("--no-sandbox")
        self.page = ChromiumPage(co)
        self.page.set.window.hide()

        # 初始化快捷键绑定
        self.init_shortcuts()
        # 初始化入住时间和入园时间为当天
        self.init_dates()
        # 填充酒店名称到 comboBox
        self.load_hotels()
        # 加载套餐数据
        self.load_packages()
        # 加载酒店链接数据
        self.load_links()
        # 加载门票价格
        self.load_ticket_prices()
        # 初始化数值
        self.init_values()


        # 检查数据格式
        self.room_num_lineEdit.editingFinished.connect(self.validate_all_inputs)
        self.room_night_lineEdit.editingFinished.connect(self.validate_all_inputs)
        self.ticket_of_adult_lineEdit.editingFinished.connect(self.validate_all_inputs)
        self.ticket_of_child_lineEdit.editingFinished.connect(self.validate_all_inputs)
        self.package_price_lineEdit.editingFinished.connect(self.validate_all_inputs)
        self.hotel_price_lineEdit.editingFinished.connect(self.validate_all_inputs)

        # 绑定复选框的 stateChanged 信号到处理方法
        self.display_info_checkBox.stateChanged.connect(self.handle_display_params)
        # 绑定前一天按钮的点击事件到方法
        self.last_day_pushButton.clicked.connect(self.set_next_day_entry_time)
        # 绑定 hotel_comboBox 的选择改变信号到方法
        self.hotel_comboBox.currentIndexChanged.connect(self.load_room_types)
        # 绑定与套餐相关字段的变化信号到处理方法
        self.hotel_comboBox.currentIndexChanged.connect(self.update_package_price)
        self.is_two_checkBox.stateChanged.connect(self.update_package_price)
        self.room_num_lineEdit.editingFinished.connect(self.update_package_price)
        self.ticket_of_adult_lineEdit.editingFinished.connect(self.update_package_price)
        self.ticket_of_child_lineEdit.editingFinished.connect(self.update_package_price)
        # 根据套餐价格反选对应套餐内容
        self.package_price_lineEdit.editingFinished.connect(self.select_package_by_price)
        # 将点击查价按钮绑定函数
        self.check_price_pushButton.clicked.connect(self.open_price_url)
        # 绑定确认按钮的点击事件到 confirm 方法
        self.ok_pushButton.clicked.connect(self.confirm)
        # 将 adjust_dates 方法连接到日期修改事件
        self.checkin_dateEdit.dateChanged.connect(self.adjust_checkin_dates)
        self.entry_dateEdit.dateChanged.connect(self.adjust_dates)
        # 单酒店按钮逻辑
        self.single_hotel_checkBox.stateChanged.connect(self.single_hotel_button_control)
        # 点击确认信息按钮
        self.ok_info_pushButton.clicked.connect(self.confirm_info)
        self.v_pushButton.clicked.connect(self.check_update)
        # 连接信号到槽函数
        self.show_warning_signal.connect(self.show_warning_message)
        # 创建快捷键，` 键
        shortcut = QShortcut(QKeySequence("F7"), self)
        # 绑定快捷键到方法
        shortcut.activated.connect(self.open_price_url_old)


    def init_icon(self):
        """初始化图标"""
        svg_renderer = QSvgRenderer('main.svg')
        pixmap = QPixmap(128, 128)  # 设置图标大小
        pixmap.fill(Qt.transparent)
        painter = QPainter(pixmap)
        svg_renderer.render(painter)
        painter.end()
        # 创建 QIcon 并设置为窗口图标
        icon = QIcon(pixmap)
        self.setWindowIcon(icon)
        self.setWindowTitle('港迪计算器')

    def init_shortcuts(self):
        """初始化快捷键绑定"""
        QShortcut(QKeySequence("F1"), self).activated.connect(self.check_price)
        QShortcut(QKeySequence("F2"), self).activated.connect(self.confirm)
        QShortcut(QKeySequence("F3"), self).activated.connect(self.confirm_info)
        QShortcut(QKeySequence("F4"), self).activated.connect(self.display_params)
        QShortcut(QKeySequence("F5"), self).activated.connect(self.display_compensation)
        QShortcut(QKeySequence("F6"), self).activated.connect(self.two_day_ticket)

    def init_dates(self):
        """初始化入住时间和入园时间为当天"""
        current_date = QDate.currentDate()
        self.checkin_dateEdit.setDate(current_date)
        self.entry_dateEdit.setDate(current_date)
        print(f"入住时间和入园时间已设置为: {current_date.toString(Qt.ISODate)}")

    def load_hotels(self):
        """读取 hotels.json 文件并填充酒店名称到 hotel_comboBox"""
        try:
            with open('hotels.json', 'r', encoding='utf-8') as file:
                data = json.load(file)
                self.hotels_data = data.get('hotels', [])
                for hotel in self.hotels_data:
                    self.hotel_comboBox.addItem(hotel['name'])
        except Exception as e:
            print(f"读取酒店数据时出错: {e}")

    def load_packages(self):
        """读取 packages.json 文件并加载套餐数据"""
        try:
            with open('packages.json', 'r', encoding='utf-8') as file:
                data = json.load(file)
                self.packages_data = data.get('packages', [])
        except Exception as e:
            print(f"读取套餐数据时出错: {e}")

    def load_links(self):
        """读取 hotel_links.json 文件并加载套餐数据"""
        try:
            with open('hotel_links.json', 'r', encoding='utf-8') as file:
                self.links_data = json.load(file)
        except Exception as e:
            print(f"读取套餐数据时出错: {e}")

    def load_ticket_prices(self):
        """加载本地存储的门票价格数据"""
        try:
            with open('ticket_prices.json', 'r', encoding='utf-8') as file:
                self.ticket_prices = json.load(file)
            print("门票价格数据加载成功:", self.ticket_prices)
        except Exception as e:
            print(f"加载门票价格数据时出错: {e}")

    def init_values(self):
        """初始化数值"""
        self.room_num_lineEdit.setText("1")  # 间数
        self.room_night_lineEdit.setText("1")  # 晚
        self.ticket_of_adult_lineEdit.setText("1")  # 大
        self.ticket_of_child_lineEdit.setText("1")  # 小
        self.hotel_price_lineEdit.setText("0")  # 酒店价格
        self.load_room_types()
        self.update_package_price()
        self.coupon_checkbox.setChecked(True)
        self.display_price_difference_checkBox.setChecked(True)

    def load_room_types(self):
        """根据选定的酒店更新 room_type_comboBox 的内容"""
        selected_index = self.hotel_comboBox.currentIndex()
        if selected_index >= 0:
            hotel = self.hotels_data[selected_index]
            self.room_type_comboBox.clear()
            self.room_type_comboBox.addItems(hotel['room_types'])
            if hotel['input_rule'] == 1:
                single_hotel_checkbox_state = Qt.Checked
            else:
                single_hotel_checkbox_state = Qt.Unchecked
            self.single_hotel_checkBox.setCheckState(single_hotel_checkbox_state)
            self.single_hotel_button_control()

    def check_price(self):
        """查价功能触发"""
        self.open_price_url()

    def confirm(self):
        if not self.ok_pushButton.isEnabled():
            self.show_warning_message("警告","请在查价完成后点击确认")
        ca_hotel_price = Decimal(str(self.calculate_hotel_price()))
        ca_ticket_price = Decimal('0')
        if self.single_hotel_checkBox.isChecked():
            self.ticket_price_lable.setText("不适用")
            self.ticket_level_label.setText("不适用")
        else:
            ca_ticket_price = self.calculate_ticket_price()
            if ca_ticket_price is None:
                return
            ca_ticket_price = Decimal(str(ca_ticket_price))  # 计算门票总价
            self.ticket_price_lable.setText(str(ca_ticket_price))
        total_price = ca_hotel_price + ca_ticket_price
        total_price = total_price.quantize(Decimal('0.01'))
        # 检查 coupon_checkbox 是否被选中
        if self.coupon_checkbox.isChecked():
            total_price += Decimal('200')

        self.total_price_label.setText(str(total_price))
        if int(self.ticket_of_child_lineEdit.text()) <= 0:
            ticket_child_str = ""
        else:
            ticket_child_str = self.ticket_of_child_lineEdit.text()+"小"
        if self.is_two_checkBox.isChecked():
            ticket_level_str = "两日"
        else:
            ticket_level_str = "1日"
        ticket_str = f"+{self.ticket_of_adult_lineEdit.text()}大{ticket_child_str}{ticket_level_str}票"
        entry_date = self.entry_dateEdit.date().toString("M月d号")
        entry_date_str = f"，{entry_date}入园"
        if self.single_hotel_checkBox.isChecked():
            ticket_str = ""
            entry_date_str = ""
        # 获取用户输入的入住和入园时间
        checkin_date = self.checkin_dateEdit.date().toString("M月d号")
        pakcage_price = Decimal(str(self.package_price_lineEdit.text()))
        price_str = ""
        if total_price-pakcage_price <= 0:
            price_str = "无需补差"
        else:
            if not self.display_price_difference_checkBox.isChecked():
                price_str = f"目前总价是:{total_price}"
            else:
                price_str = f"目前总价是:{total_price}，需要补差价{total_price}-{pakcage_price}={total_price-pakcage_price}"
        # 填充字符串信息
        info_str = (
            f"{self.hotel_comboBox.currentText()} 不含早 { self.room_type_comboBox.currentText() }{self.room_num_lineEdit.text()}间{self.room_night_lineEdit.text()}晚"
            f"{ticket_str}，"
            f"{checkin_date}入住{entry_date_str}，{price_str}"
        )
        # 复制字符串到剪贴板
        clipboard = QApplication.clipboard()
        clipboard.setText(info_str)
        print(info_str)

    def  calculate_hotel_price(self):
        """根据用户选择和输入计算酒店价格"""
        # 获取用户输入的基础价格
        base_price = float(self.hotel_price_lineEdit.text()) * int(self.room_night_lineEdit.text())
        selected_hotel = self.hotel_comboBox.currentText()
        check_in_str = self.checkin_dateEdit.text()  # 入住时间（格式: yyyy/MM/dd）

        try:
            check_in_date = datetime.strptime(check_in_str, '%Y/%m/%d')
        except ValueError as e:
            print(f"日期格式转换错误: {e}")
            return 0

        # 计算入住天数
        total_nights = int(self.room_night_lineEdit.text())
        highest_price = 0

        room_type = self.room_type_comboBox.currentText()
        for day in range(total_nights):
            current_date = check_in_date + timedelta(days=day)
            current_price = base_price
            # 判断酒店类型并应用价格规则
            if selected_hotel == '迪士尼乐园酒店':
                current_price = base_price / 0.92
            elif selected_hotel == '探索家酒店':
                if current_date.month == 2 and current_date.year == 2025:
                    if current_date <= datetime(2025, 2, 22):
                        current_price = base_price / 0.92
                    elif datetime(2025,2,23) == current_date or datetime(2025,2,27) <= current_date <= datetime(2025,2,28):
                        current_price = base_price + (100 * total_nights)
                    elif datetime(2025,2,24) <= current_date <= datetime(2025,2,26):
                        if room_type == "豪华客房":
                            current_price = base_price + (50 * total_nights)
                        else:
                            current_price = base_price + (100 * total_nights)
                            self.show_warning_signal.emit("警告！","此天加价规则中建议选择房型为豪华房 加价+50 其他房型+100")
                    else:
                        self.show_warning_signal.emit("警告！","未匹配2月内的任何加价 使用默认/0.92加价")
                        current_price  = base_price / 0.92
                elif current_date.month == 3 and current_date.year == 2025:
                    if current_date.weekday() in [4,5,6]:
                        current_price = base_price + (100 * total_nights)
                    else:
                        current_price  = base_price + (50 * total_nights)
                elif current_date.month == 4 and current_date.year == 2025:
                    if datetime(2025,4,3) <= current_date <= datetime(2025,4,6):
                        current_price = base_price / 0.92
                    elif datetime(2025, 4, 30) == current_date:
                        current_price = base_price / 0.92
                    elif current_date.weekday() in [3,4,5,6]:
                        current_price = base_price + (100 * total_nights)
                    else:
                        current_price  = base_price + (50 * total_nights)
                elif current_date.month == 5 and current_date.year == 2025:
                    if datetime(2025,5,1) <= current_date <= datetime(2025,5,5):
                        current_price = base_price / 0.92
                    elif datetime(2025,5,30) <= current_date <= datetime(2025,5,31):
                        current_price = base_price / 0.92
                    elif current_date.weekday() in [3,4,5,6]:
                        current_price = base_price + (100 * total_nights)
                    else:
                        current_price  = base_price + (50 * total_nights)
                else:
                    self.show_warning_signal.emit("警告！","没有匹配上所有酒店加价规则，已使用默认加价规则:除0.92")
                    current_price  = base_price / 0.92
            elif selected_hotel == '好莱坞酒店':
                current_price = base_price / 0.92
            # 取最高价格
            highest_price = max(highest_price, round(current_price, 0))

        self.hotel_price_label.setText(str(highest_price))
        return highest_price

    def get_current_ticket_level(self):
        """根据用户输入的入园时间获取当前门票等级"""
        entry_date = self.entry_dateEdit.date().toString("yyyy-MM-dd")  # 获取用户输入的入园时间
        ticket_level = "不适用"
        if self.is_two_checkBox.isChecked():
            self.ticket_level_label.setText("两日票")
            return "两日"

        # 根据已保存的门票等级数据进行查询
        if entry_date in self.ticket_levels:
            if self.ticket_levels[entry_date]["closed"]:
                QMessageBox.warning(self, "警告", f"{entry_date} 该日期闭园，请选择其他日期")
                return
            else:
                # 提取门票等级
                ticket_level = self.ticket_levels[entry_date]["type"].replace("Tier ", "")
        else:
            QMessageBox.warning(self, "警告", f"未找到 {entry_date} 的门票等级，请检查日期")
            return
        self.ticket_level_label.setText(str(ticket_level))
        return ticket_level

    def calculate_ticket_price(self):
        """计算门票价格"""
        entry_date = self.entry_dateEdit.text()  # 获取入园时间
        entry_in_date = datetime.strptime(entry_date, '%Y/%m/%d')
        current_level = self.get_current_ticket_level()  # 获取当前入园时间的门票等级
        if current_level is None:
            return None
        ticket_price = self.ticket_prices.get(str(current_level), {"adult": 0, "child": 0})
        adult_price = ticket_price["adult"]
        child_price = ticket_price["child"]

        num_adults = int(self.ticket_of_adult_lineEdit.text())
        num_children = int(self.ticket_of_child_lineEdit.text())

        total_ticket_price = (num_adults * adult_price) + (num_children * child_price)

        return total_ticket_price

    def confirm_info(self):
        """确认信息功能触发，点击复选框"""
        checkin_date = self.checkin_dateEdit.date()
        entry_date = self.entry_dateEdit.date()
        if self.is_two_checkBox.isChecked():
            ticket_info_str = "2日"
        else:
            ticket_info_str = "1日"
        ticket_all_str = f"【门票入园】：{self.ticket_of_adult_lineEdit.text()}大{self.ticket_of_child_lineEdit.text()}小{ticket_info_str}票{entry_date.month()}月{entry_date.day()}日入园。凭预约时填写的邮箱收到的二维码(一票一码）景区门口直接扫码使用。如需尊享卡或任何问题可加我们售后V信：19168985658，祝您旅途愉快。\n"
        if self.single_hotel_checkBox.isChecked():
            ticket_all_str = ""
        room_type = self.room_type_comboBox.currentText()
        if room_type != '':
            room_type_str = f'（{room_type}）'
        else:
            room_type_str = room_type
        str = (
            f"【酒店办理入住】：{checkin_date.month()}月{checkin_date.day()}日凭入住人（）通行证或护照原件在 {self.hotel_comboBox.currentText()}{room_type_str}前台办理入住不含早 {self.room_num_lineEdit.text()}间{self.room_night_lineEdit.text()}晚\n"
            f"{ticket_all_str}"
            f"【注意】订单预约成功，不退不改！"
               )
        clipboard = QApplication.clipboard()
        clipboard.setText(str)
        print(str)

    def display_params(self):
        """显示参数功能触发，点击复选框"""
        print("显示参数功能触发")
        self.display_info_checkBox.click()

    def handle_display_params(self):
        """
        根据复选框状态调整窗口大小
        如果复选框被选中，将窗口大小调整为 (179, 714)
        否则，将窗口大小调整为 (179, 558)
        """
        if self.display_info_checkBox.isChecked():
            self.resize(179, 714)
        else:
            self.resize(179, 558)

    def display_compensation(self):
        """显示补差功能触发，点击复选框"""
        print("显示补差功能触发")
        self.display_price_difference_checkBox.click()

    def two_day_ticket(self):
        """两日票功能触发，点击复选框"""
        print("两日票功能触发")
        self.is_two_checkBox.click()

    def set_next_day_entry_time(self):
        """将入园时间设置为入住时间后一天"""
        current_date = self.checkin_dateEdit.date()
        next_day = current_date.addDays(1)
        self.entry_dateEdit.setDate(next_day)
        print(f"入园时间已设置为: {next_day.toString(Qt.ISODate)}")

    def update_package_price(self):
        """根据当前选择和输入更新套餐价格"""
        # 如果是自动更新期间，跳过此方法
        if self.is_updating_package:
            return
        selected_hotel = self.hotel_comboBox.currentText()
        num_nights = int(self.room_num_lineEdit.text())
        num_adults = int(self.ticket_of_adult_lineEdit.text())
        num_children = int(self.ticket_of_child_lineEdit.text())
        is_two_days_ticket = self.is_two_checkBox.isChecked()

        if self.single_hotel_checkBox.isChecked():
            num_adults = 0
            num_children = 0
            is_two_days_ticket = 0

        for package in self.packages_data:
            if (selected_hotel in package['hotels'] and
                    package['nights'] == num_nights and
                    package['adults'] == num_adults and
                    package['children'] == num_children and
                    package['two_days_ticket'] == int(is_two_days_ticket)):
                self.package_price_lineEdit.setText(str(package['price']))
                return

        self.hotel_price_lineEdit.setText("0")
        print("没有找到匹配的套餐价格，价格已设置为: 0")

    def select_package_by_price(self):
        """根据用户输入的套餐价格选择对应的套餐"""
        # 启用标志位
        self.is_updating_package = True

        input_price = self.package_price_lineEdit.text()

        input_price = float(input_price)
        selected_hotel = self.hotel_comboBox.currentText()

        for package in self.packages_data:
            if package['price'] == input_price and selected_hotel in package['hotels']:
                self.is_two_checkBox.setChecked(package['two_days_ticket'] == 1)
                self.room_night_lineEdit.setText(str(package['nights']))
                self.ticket_of_adult_lineEdit.setText(str(package['adults']))
                self.ticket_of_child_lineEdit.setText(str(package['children']))
                if package['adults'] == 0 and package['children'] == 0:
                    self.single_hotel_checkBox.setChecked(True)
                break

        # 禁用标志位
        self.is_updating_package = False

    def open_price_url_old(self):
        """根据用户选择生成并打开价格查询网址"""
        # 从 hotels_data 中获取当前用户选择的酒店数据
        selected_hotel_name = self.hotel_comboBox.currentText()
        selected_hotel = next((hotel for hotel in self.hotels_data if hotel['name'] == selected_hotel_name), None)

        if not selected_hotel:
            print("未找到匹配的酒店数据")
            return
        # 酒店ID
        hotel_id = selected_hotel['hotelId']
        # 平台ID
        price_id = selected_hotel['priceId']

        # 根据 price_id 查找平台代码
        platform_code = next((platform_code for platform_code, data in self.links_data.items() if
                              data['platform_code'] == int(price_id)), None)

        if not platform_code:
            print("未找到对应的平台代码")
            return

            # 获取对应平台的 URL 模板
        url_template = self.links_data[platform_code]['url']

        check_in = self.checkin_dateEdit.text()
        check_out = self.calculate_check_out_date()
        # 转换日期格式
        try:
            check_in_date = datetime.strptime(check_in, '%Y/%m/%d')
            check_in = check_in_date.strftime('%Y-%m-%d')
        except ValueError as e:
            print(f"日期格式转换错误: {e}")
            return
        adult = self.ticket_of_adult_lineEdit.text()
        children = self.ticket_of_child_lineEdit.text()
        crn = self.room_num_lineEdit.text()

        url = url_template.format(hotelId=hotel_id, checkIn=check_in, checkOut=check_out,
                                  adult=adult, children=children, crn=crn)
        webbrowser.open(url)

    def open_price_url(self):
        """根据用户选择生成并打开价格查询网址"""
        # 从 hotels_data 中获取当前用户选择的酒店数据
        self.hotel_price_lineEdit.setText("-1")
        self.hotel_price_lineEdit.setEnabled(False)
        self.ok_pushButton.setEnabled(False)
        selected_hotel_name = self.hotel_comboBox.currentText()
        selected_hotel = next((hotel for hotel in self.hotels_data if hotel['name'] == selected_hotel_name), None)

        if not selected_hotel:
            print("未找到匹配的酒店数据")
            return
        # 酒店ID
        hotel_id = selected_hotel['hotelId']
        # 平台ID
        price_id = selected_hotel['priceId']

        # 根据 price_id 查找平台代码
        platform_code = next((platform_code for platform_code, data in self.links_data.items() if
                              data['platform_code'] == int(price_id)), None)

        if not platform_code:
            print("未找到对应的平台代码")
            return

            # 获取对应平台的 URL 模板
        url_template = self.links_data[platform_code]['url']

        check_in = self.checkin_dateEdit.text()
        check_out = self.calculate_check_out_date()
        # 转换日期格式
        try:
            check_in_date = datetime.strptime(check_in, '%Y/%m/%d')
            check_in = check_in_date.strftime('%Y-%m-%d')
        except ValueError as e:
            print(f"日期格式转换错误: {e}")
            return
        adult = self.ticket_of_adult_lineEdit.text()
        children = self.ticket_of_child_lineEdit.text()
        crn = self.room_num_lineEdit.text()

        url = url_template.format(hotelId=hotel_id, checkIn=check_in, checkOut=check_out, crn=crn)

        def execute_task(url):
            # start_time = time.time()  # 开始时间
            # print(f"开始时间：{start_time}")
            try:
                tab = self.page.new_tab(url)
            except PageDisconnectedError  as e:
                print(f"捕获到PageDisconnectedError错误: {str(e)}")
                # 重新初始化浏览器页面
                co = ChromiumOptions().set_argument("--no-sandbox")
                self.page = ChromiumPage(co)
                tab = self.page.new_tab(url)
            # open_url_time = time.time()
            # print(f"打开浏览器链接耗时， {open_url_time-start_time}")
            # 初始化变量
            price = None
            room_type = self.room_type_comboBox.currentText()
            is_over = False
            while not is_over:
                if room_type == '':
                    # 用户未选择房型，获取第一个价格
                    room_element = tab.ele("@class=roomname")
                else:
                    # 用户选择了房型，查找对应房型的价格
                    room_element = tab.ele(f"@@class=roomname@@text()={room_type}", timeout=3)
                # check_room_tiket_time = time.time()
                # print(f"查看房型标签耗时， {time.time() - open_url_time}")
                if isinstance(room_element, NoneElement):
                    if room_type == '':
                        # 用户未选择房型，获取第一个价格
                        room_element = tab.ele("@class:commonRoomCard-title")
                    else:
                        # 用户选择了房型，查找对应房型的价格
                        room_element = tab.ele(f"@@class:commonRoomCard-title@@text()={room_type}", timeout=3)
                    if isinstance(room_element, NoneElement):
                        sold_out_tab = tab.ele(locator="@class^soldOut-tripMessageBold", timeout=1)
                        if not isinstance(sold_out_tab, NoneElement) and "本酒店目前不接受预定" in sold_out_tab.text:
                            self.show_warning_signal.emit("警告！", f"该酒店无房！")
                        else:
                            self.show_warning_signal.emit("警告！", f"没找到房型{room_type} 请手动输入价格")
                        self.hotel_price_lineEdit.setEnabled(True)
                        self.ok_pushButton.setEnabled(True)
                        tab.scroll.to_location(0, 700)
                        tab.set.window.max()
                        break
                    else:
                        price_display_all = room_element.parent().parent()
                        saleRoom__ruhNI = price_display_all.ele(".saleRoom__ruhNI")
                        div_elements = saleRoom__ruhNI.children()[1:3]
                        # check_price_tiket_time = time.time()
                        # print(f"查看价格标签耗时， {check_price_tiket_time -check_room_tiket_time}")
                        # 初始化存储符合条件的价格和对应的 div
                        price_data = []
                        i = 1
                        # 遍历前三个 div
                        for div in div_elements:
                            # 查找该 div 下 class 为 bm-item 的元素的 span 内容
                            if is_over:
                                break
                            if "解锁优惠" in div.text:
                                self.show_warning_signal.emit("警告！", "请先登录携程")
                                tab.scroll.to_location(0, 700)
                                tab.set.window.max()
                                is_over = True
                                break
                            bm_item_span = div.ele(
                                locator='.smarticon u-icon u-icon-ic_new_nonbreakfast u-icon_ic_new_nonbreakfast saleRoomItemBox-reservationNotesInfo_basicSaleRoomItem_icon__m5R61',
                                timeout=0.1)
                            if bm_item_span and bm_item_span.parent().text.strip() == "无早餐":
                                price_span = div.ele('@class^saleRoomItemBox-priceBox-displayPrice')
                                prcie_span_child = price_span.child()
                                price_str = prcie_span_child.inner_html
                                try:
                                    price = Decimal(re.sub(r'[^\d]', '', price_str))
                                except InvalidOperation:
                                    self.show_warning_signal.emit(f"无法转换为 Decimal 的数据：'{price_str}'")
                                price_data.append(price)
                            # get_time_price_time = time.time()
                            # print(f"查找第{i}价格耗时：{get_time_price_time - check_price_tiket_time}")
                            i += 1
                        # get_all_prices_time = time.time()
                        # print(f"获取所有价格总耗时：{get_all_prices_time - check_price_tiket_time}")
                else:
                    roomcard = room_element.parent().parent()
                    salecardlist_rooms = roomcard.ele("@class=salecardlist-rooms")
                    div_elements = salecardlist_rooms.children()[:3]
                    price_data = []
                    i = 1
                    # 遍历前三个 div
                    for div in div_elements:
                        # 查找该 div 下 class 为 bm-item 的元素的 span 内容
                        if '售完' in div.text:
                            is_over = True
                            self.show_warning_signal.emit("警告！", "该酒店无房！")
                            break
                        if is_over:
                            break
                        if "解锁优惠" in div.text or "登录看低价" in div.text:
                            self.show_warning_signal.emit("警告！", "请先登录携程")
                            tab.scroll.to_location(0, 700)
                            tab.set.window.max()
                            is_over = True
                            break
                        bm_item_span = div.ele(
                            locator='.bm-item',
                            timeout=0.1).children()[0]
                        if bm_item_span and bm_item_span.text.strip() == "无早餐":
                            price_span = div.ele('@class=price-display price-display-hover')
                            price_str = price_span.text
                            try:
                                price = Decimal(re.sub(r'[^\d]', '', price_str))
                            except InvalidOperation:
                                self.show_warning_signal.emit("错误！", f"无法转换为 Decimal 的数据：'{price_str}'")
                            price_data.append(price)
                        # get_time_price_time = time.time()
                        # print(f"查找第{i}价格耗时：{get_time_price_time - check_price_tiket_time}")
                        i += 1
                if price_data and not is_over:
                    lowest_price = min(price_data)
                    self.hotel_price_lineEdit.setText(lowest_price.to_eng_string())
                    self.ok_pushButton.setEnabled(True)
                    self.hotel_price_lineEdit.setEnabled(True)
                    tab.close()
                    break

        # 创建线程池执行异步任务
        executor = ThreadPoolExecutor(max_workers=1)
        executor.submit(execute_task, url)

    def calculate_check_out_date(self):
        """计算退房日期"""
        # 从 checkin_dateEdit 控件获取入住日期
        check_in_date = self.checkin_dateEdit.date()
        # 从 room_night_lineEdit 控件获取晚数
        num_nights = int(self.room_night_lineEdit.text())
        # 计算退房日期
        check_out_date = check_in_date.addDays(num_nights)
        # 返回格式化后的退房日期
        return check_out_date.toString("yyyy-MM-dd")

    def adjust_dates(self):
        today = QDate.currentDate()
        check_in_date = self.checkin_dateEdit.date()
        entry_date = self.entry_dateEdit.date()

        # 如果入住时间或入园时间早于今天，则设置为今天
        if check_in_date < today:
            check_in_date = today
            self.checkin_dateEdit.setDate(today)

        if entry_date < today:
            entry_date = today
            self.entry_dateEdit.setDate(today)

        # 如果入住时间大于入园时间，则将入园时间设置为入住时间
        if check_in_date > entry_date:
            entry_date = check_in_date
            self.entry_dateEdit.setDate(check_in_date)

        # 如果入园时间早于入住时间，则将入住时间设置为入园时间
        if entry_date < check_in_date:
            check_in_date = entry_date
            self.checkin_dateEdit.setDate(entry_date)

    def adjust_checkin_dates(self):
        self.entry_dateEdit.setDate(self.checkin_dateEdit.date())
        self.adjust_dates()

    def single_hotel_button_control(self):
        is_checked = self.single_hotel_checkBox.isChecked()

        # 禁用或启用控件
        self.is_two_checkBox.setEnabled(not is_checked)  # 两日票
        self.last_day_pushButton.setEnabled(not is_checked)  # 次日入园按钮

        # 这里可以加入更多相关的控件禁用或启用
        # 假设 self.adult_input 和 self.children_input 分别表示大输入框和小输入框
        self.ticket_of_adult_lineEdit.setEnabled(not is_checked)  # 大输入框
        self.ticket_of_child_lineEdit.setEnabled(not is_checked)  # 小输入框
        self.entry_dateEdit.setEnabled(not is_checked)  # 入园时间选择框

        self.update_package_price()

    def validate_all_inputs(self):
        try:
            room_count = int(self.room_num_lineEdit.text())
        except ValueError as e:
            self.room_num_lineEdit.setText("1")
            self.show_warning_signal.emit("输入类型错误", "房间数输入框只能为整数数字")
            return False
        try:
            room_night = int(self.room_night_lineEdit.text())
        except ValueError as e:
            self.room_night_lineEdit.setText("1")
            self.show_warning_signal.emit("输入类型错误", "晚数输入框只能为整数数字")
            return False
        try:
            adult_count = int(self.ticket_of_adult_lineEdit.text())
        except ValueError as e:
            self.ticket_of_adult_lineEdit.setText("1")
            self.show_warning_signal.emit("输入类型错误", "大人输入框只能为整数数字")
            return False
        try:
            child_count = int(self.ticket_of_child_lineEdit.text())
        except ValueError as e:
            self.ticket_of_child_lineEdit.setText("1")
            self.show_warning_signal.emit("输入类型错误", "小孩输入框只能为整数数字")
            return False
        try:
            package_price = float(self.package_price_lineEdit.text())
        except ValueError as e:
            self.package_price_lineEdit.setText("0")
            self.show_warning_signal.emit("输入类型错误", "套餐输入框只能为数字")
            return False
        try:
            hotel_price = float(self.hotel_price_lineEdit.text())
        except ValueError as e:
            self.hotel_price_lineEdit.setText("0")
            self.show_warning_signal.emit("输入类型错误", "酒店价格输入框只能为数字")
            return False

        return True

    def check_update(self):
        try:
            check_url = "https://gitee.com/hjfjyc/gangdi_calc/releases/latest"
            update_exe = "./update.exe"
            original_program = "Main_gangdi_calc.exe"
            subprocess.Popen([update_exe, '--version', self.current_version, '--check_url', check_url, '--original_program',
                              original_program])
        except FileNotFoundError as e:
            QMessageBox.critical(None, "检查更新失败", "找不到更新程序update.exe")
    def check_update(self):
        try:
            check_url = "https://gitee.com/hjfjyc/gangdi_calc/releases/latest"
            update_exe = "./update.exe"
            original_program = "Main_gangdi_calc.exe"
            subprocess.Popen([update_exe, '--version', self.current_version, '--check_url', check_url, '--original_program',
                              original_program])
        except FileNotFoundError as e:
            QMessageBox.critical(None, "检查更新失败", "找不到更新程序update.exe")

    def show_warning_message(self, title, message):
        # 显示警告消息框
        QMessageBox.warning(None, title, message)

    def fetch_ticket_levels(self):
        """获取并保存门票等级数据"""
        try:
            response = requests.get(
                "https://www.hongkongdisneyland.com/reservation-svc/pub/retrieve-facility-schedule/")
            response_data = response.json()

            if response_data.get("status") == "success":
                schedules = response_data["data"].get("schedules", [])
                for schedule in schedules:
                    self.ticket_levels[schedule["date"]] = {
                        "type": schedule["type"],
                        "closed": schedule["closed"]
                    }
            else:
                QMessageBox.warning(self, "警告", "获取门票等级信息失败，请稍后再试")

        except requests.exceptions.RequestException as e:
            QMessageBox.warning(self, "警告", f"请求失败：{str(e)}")

def check_calendar_update(local_modify_time, mainapp, app):

        url = "https://docs.qq.com/api/list/recent"
        payload = {"parent_id": "recent", "offset": 0, "count": 100, "order_by": 1, "descending": True} # 如果有需要发送的POST数据，请在此补充
        headers = {
            "Content-Type": "application/json",
        }
        cookies = {
            "uid": "144115352761191142",
            "uid_key": "EOP1mMQHGjBpTy9pL1pUd3VXMzJtajZFYlNzdElBSWZqUzRPbXhLcDBVd2Y0MEVJc2FWenR3PT0igQJleUpoYkdjaU9pSkJRME5CVEVjaUxDSjBlWEFpT2lKS1YxUWlmUS5leUpVYVc1NVNVUWlPaUl4TkRReE1UVXpOVEkzTmpFeE9URXhORElpTENKV1pYSWlPaUl4SWl3aVJHOXRZV2x1SWpvaWMyRmhjMTkwYjJNaUxDSlNaaUk2SW14WlZVZEZiU0lzSW1WNGNDSTZNVGMwTWpZeE16VTRPU3dpYVdGMElqb3hOelF3TURJeE5UZzVMQ0pwYzNNaU9pSlVaVzVqWlc1MElFUnZZM01pZlEuWGtwZDV1SVAtWHhkSTBPWV9WdHhUU2hFX29nNjdwZmM1aUR4SVhiOUozNCjV2Pi%2BBkjB2oG9Bg%3D%3D" }

        try:
            # 发起POST请求
            response = requests.post(url, json=payload, headers=headers, cookies=cookies)
            response.raise_for_status()  # 检查请求是否成功
            if response.json()['msg'] == '尚未登录':
                mainapp.show_warning_message("错误", f"腾讯文档登录过期请更新")
                mainapp.close()
                app.quit()
                sys.exit(0)
            result = response.json()['result']['files']

            calendar_file = next(
                (item["entry"] for item in result if "entry" in item and item["entry"].get("name") == "日历报价"),
                None
            )
            if not calendar_file:
                mainapp.show_warning_message("错误", "未找到名为'日历报价'的文件")
                return

            # 获取文件的modify_time
            server_modify_time = calendar_file.get("modify_time")
            if not server_modify_time:
                mainapp.show_warning_message("错误", "未找到'日历报价'的修改时间")
                mainapp.close()
                app.quit()
                sys.exit(0)
                return

            # 比较时间戳
            if local_modify_time != server_modify_time:
                # 弹窗提醒开发者
                mainapp.show_warning_message("提醒", "日历报价已更新，请更新本地加价规则！")
                mainapp.close()
                app.quit()
                sys.exit(0)

        except requests.RequestException as e:
            mainapp.show_warning_message("网络错误", f"请求失败: {e}")
            mainapp.close()
            app.quit()
            sys.exit(0)
        except Exception as e:
            mainapp.show_warning_message("错误", f"发生未知错误: {e}")
            mainapp.close()
            app.quit()
            sys.exit(0)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    try:
        current_version = "v202502210000"
        check_url = "https://gitee.com/hjfjyc/gangdi_calc/releases/latest"
        update_exe = "./update.exe"
        original_program = "Main_gangdi_calc.exe"
        subprocess.Popen([update_exe, '--version', current_version, '--check_url', check_url, '--original_program', original_program])
    except FileNotFoundError as e:
        QMessageBox.critical(None, "检查更新失败", "找不到更新程序update.exe")
    try:
        main_app = MainApp(current_version)
        main_app.show()
        last_modify_time = '1740039193674'
        # 在启动事件循环前调用日历检查
        check_calendar_update(last_modify_time, main_app, app)
        sys.exit(app.exec_())
    except Exception as e:
        print(f"程序发生错误: {e}")
